
#include <vector>
#include <stack>

#include "c_interaction.h"

namespace dhd
{
namespace client
{
   namespace
   {
      class IInteraction : public Interaction
      {
       public:
         virtual void on_zero_refcount();
      };
      
      typedef std::stack< IInteraction *, std::vector<IInteraction *> > InteractionStack;
      
      boost::mutex     g_istack_mutex;
      InteractionStack g_istack;
      bool             g_istack_deleted = false;
      
      void IInteraction::on_zero_refcount()
      {
          clear();
       
          boost::mutex::scoped_lock guard( g_istack_mutex );
          
          if ( g_istack_deleted )
              delete this; // Process is shutting down
          else
              g_istack.push( this );
      }
   } // end anonymous namespace
   
   
   Interaction::Interaction() : 
       notify_on_reply(false), have_reply(false), 
       require_reply(false), do_callback(false),
       request_id(0),
       reply_error_on_disconnect(false)
   {}
   
   
   void Interaction::clear()
   {
       request.Clear();
       reply.Clear();
       notify_on_reply = false;
       have_reply      = false;
       require_reply   = false;
       do_callback     = false;
       request_id      = 0;
       pbuffer         = 0;
       reply_error_on_disconnect = false;
   }
   
   
   void Interaction::set_async_complete_callback( const AsyncCompleteHandler & cb )
   {
       async_callback = cb;
       do_callback    = true;
   }
   
   
   void Interaction::wait_for_reply()
   {
       assert( require_reply );
       
       boost::mutex::scoped_lock guard( imutex );
       while ( !have_reply )
           icv.wait( guard );
   }
   
   
   void Interaction::notify_reply_received()
   {
       assert( !have_reply );
       
       have_reply = true;
       
       if (do_callback)
           async_callback( reply );
       
       icv.notify_one();
   }
   
   
   void delete_interaction_cache()
   {
       boost::mutex::scoped_lock guard( g_istack_mutex );
       
       while ( !g_istack.empty() )
       {
           delete g_istack.top();
           g_istack.pop();
       }
       
       g_istack_deleted = true;
   }
   
   
   PInteraction allocate_interaction( bool reply_required )
   {
       boost::mutex::scoped_lock guard( g_istack_mutex );
       
       IInteraction * i = 0;
       
       if ( g_istack.empty())
           i = new IInteraction;
       else
       {
           i = g_istack.top();
           g_istack.pop();
       }
       
       i->set_reply_required( reply_required );
       
       assert( !i->check_reply() );
       
       return PInteraction( i );
   }

}// end namespace dhd::client
}// end namespace dhd

